#include "cpu.h"
#include "Inst.h"
#include "Exec.h"

typedef struct {
  uint8_t  valid = 0;
  uint64_t pc;
  uint32_t inst;
  uint8_t  skip;
  uint8_t  isRVC;
  uint8_t  scFailed;
  uint8_t  fused;
  uint8_t  wen;
  uint8_t  wdest;
  uint64_t wdata;
} instr_commit_t;

bool cpu::step(){
    
    uint32_t inst = read(curContext.pc,4);

    curCommitState.valid     = 0;
    curCommitState.pc        = 0;
    curCommitState.inst      = 0;
    curCommitState.skip      = 0;
    curCommitState.isRVC     = 0;
    curCommitState.scFailed  = 0;
    curCommitState.fused     = 0;
    curCommitState.wen       = 0;
    curCommitState.wdest     = 0;
    curCommitState.wdata     = 0;
    brunch_valid             = 0;
    brunch_addr              = 0;

#ifdef DEBUG_INST
    printf("[inst] %08x\n",inst);
#endif
    if (inst == 0x0000006b)
        return true;

    if(inst == 0x0000007b){
        printf("%c",(uint8_t)(curContext.xregs[10]&0xff));
        return true;
    }

    if(length(inst) == 3){
        switch (opcode(inst)){

case OPCODE_LOAD      :{break;}
case OPCODE_LOAD_FP_VP:{goto illegal_exit;}
case OPCODE_CUSTOM_0  :{goto illegal_exit;}
case OPCODE_MISSC_MEM :{break;}
case OPCODE_OP_IMM    :{
    switch (funct3(inst)){
        case 0x0:{Exec_ADDI(this,inst); break;}
        // case 0x1:{if((inst>>26) == 0) Exec_SLLI(this,inst); else goto illegal_exit; break;}
        // case 0x2:{Exec_SLTI (this,inst); break;}
        // case 0x3:{Exec_SLTIU(this,inst); break;}
        // case 0x4:{Exec_XORI (this,inst); break;}
        // case 0x5:{if(funct7(inst) & 0x20) Exec_SRAI(this,inst); else Exec_SRLI(this,inst); break;}
        // case 0x6:{Exec_ORI  (this,inst); break;}
        // case 0x7:{Exec_ANDI (this,inst); break;}
        default:goto illegal_exit;
    }
    break;
}
// case OPCODE_AUIPC     :{Exec_AUIPC(this,inst); break;}
// case OPCODE_OP_IMM_32 :{
//     switch (funct3(inst)){
//     case 0x0:{Exec_ADDIW(this,inst); break;};
//     case 0x1:{Exec_SLLIW(this,inst); break;};
//     case 0x5:{
//         if(funct7(inst) == 0x00) 
//             Exec_SRLIW(this,inst);
//         else if(funct7(inst) == 0x20) 
//             Exec_SRAIW(this,inst);
//         else 
//             goto illegal_exit;
//         break;
//     };
//     default:goto illegal_exit;
//     }    
//     break;
// }
// case OPCODE_48B_0     :{goto illegal_exit;}

// case OPCODE_STORE      :{break;}
// case OPCODE_STORE_FP_VP:{goto illegal_exit;}
// case OPCODE_CUSTOM_1   :{goto illegal_exit;}
// case OPCODE_AMO        :{goto illegal_exit;}
// case OPCODE_OP         :{
//     switch (funct7(inst)){
//         case 0x00:{ 
//             switch (funct3(inst)){
//                 case 0x00: {Exec_ADD (this,inst); break;}
//                 case 0x01: {Exec_SLL (this,inst); break;}
//                 case 0x02: {Exec_SLT (this,inst); break;}
//                 case 0x03: {Exec_SLTU(this,inst); break;}
//                 case 0x04: {Exec_XOR (this,inst); break;}
//                 case 0x05: {Exec_SRL (this,inst); break;}
//                 case 0x06: {Exec_OR  (this,inst); break;}
//                 case 0x07: {Exec_AND (this,inst); break;}
//             }
//             break;
//         }
//         case 0x20:{
//             switch (funct3(inst)){
//                 case 0x00: {Exec_SUB(this,inst); break;}
//                 case 0x05: {Exec_SRA(this,inst); break;}
//                 default:goto illegal_exit;
//             }
//             break;
//         }
//         case 0x01:goto illegal_exit;
//         default:goto illegal_exit;
//     }
//     break;
// }

// case OPCODE_LUI        :{break;}
// case OPCODE_OP_32      :{
//     switch (funct3(inst)){
//         case 0x0:{
//             if(funct7(inst) == 0x00) 
//                 Exec_ADDW(this,inst);
//             else if(funct7(inst) == 0x20)
//                 Exec_SUBW(this,inst);
//             else 
//                 goto illegal_exit; 
//             break;
//         }
//         case 0x1:{Exec_SLLW(this,inst);break;}
//         case 0x5:{
//             if(funct7(inst) == 0x00)
//                 Exec_SRLW(this,inst);
//             else if (funct7(inst) == 0x20)
//                 Exec_SRAW(this,inst);
//             break;
//         }
//         default:break;
//     }
//     break;
// }
// case OPCODE_64B        :{goto illegal_exit;}

// case OPCODE_MADD    :{goto illegal_exit;}
// case OPCODE_MSUB    :{goto illegal_exit;}
// case OPCODE_NMSUB   :{goto illegal_exit;}
// case OPCODE_NMADD   :{goto illegal_exit;}
// case OPCODE_OP_FP   :{goto illegal_exit;}
// case OPCODE_VECTOR  :{goto illegal_exit;}
// case OPCODE_CUSTOM_2:{goto illegal_exit;}
// case OPCODE_48B_1   :{goto illegal_exit;}

// case OPCODE_BRANCH    :{
//     switch (funct3(inst)){
//         case 0x0:{ Exec_BEQ (this,inst); return true;}
//         case 0x1:{ Exec_BNE (this,inst); return true;}
//         case 0x4:{ Exec_BLT (this,inst); return true;}
//         case 0x5:{ Exec_BGE (this,inst); return true;}
//         case 0x6:{ Exec_BLTU(this,inst); return true;}
//         case 0x7:{ Exec_BGEU(this,inst); return true;}
//         default:goto illegal_exit;
//     }
//     return 1;
// }
// case OPCODE_JALR      :{Exec_JALR(this,inst); return true;}
// case OPCODE_RESERVED_0:{goto illegal_exit;}
// case OPCODE_JAL       :{Exec_JAL (this,inst); return true;}
// case OPCODE_SYSTEM    :{break;}
// case OPCODE_RESERVED_1:{goto illegal_exit;}
// case OPCODE_CUSTOM_3  :{goto illegal_exit;}
// case OPCODE_80B       :{goto illegal_exit;}
    
}}else{
    printf("!!! not implement instruction !!! \n");
}

    return true;

illegal_exit:
    printf("inst illegal\n");
    return false;
}

bool cpu::stateSync(){
    if (curCommitState.valid && curCommitState.wen){
        curContext.xregs[curCommitState.wdest] = curCommitState.wdata;
    }

    if(curContext.xregs[10] == 0x1){
        printf("  -->  HIT A GOOD TRAP\n");
        return 0;
    } else{
        contextDump();
        printf("  -->  HIT A BAD TRAP , BAD CODE IS %ld\n",curContext.xregs[10]);
        return -1;
    }
}

void cpu::contextDump() {
    printf("\n========================================>>>   Context   <<<======================================\n\n");
    for (int i = 0; i < 32; i ++) {
    printf("%4s: 0x%016lx ", riscv_abiX[i],curContext.xregs[i]);
    if (i % 4 == 3) {
      printf("\n");
    }}
    printf("\n==========================================>>>   End   <<<========================================\n\n");

}